// package 状态树
package state

import (
	"osiris/config"
	"osiris/core/routine"
	"osiris/dto"
	"osiris/errors"
	"osiris/logger"
	"osiris/ocrypto/ecdsa"
)

// DepositTxHandler 代币充值交易
type DepositTxHandler struct {
	TxData dto.TxData
}

func (txHandler DepositTxHandler) Verify(tries ...interface{}) bool {
	trie := tries[0]
	tempAccountTrie, ok := trie.(*AccountStateTrie)
	if !ok {
		logger.Warn(map[string]interface{}{"[state] [Verify Deposit TX]": "unknown trie!"})
		return false
	}

	//检查账户地址是否存在
	currentNonce, exist := tempAccountTrie.getNonce(txHandler.TxData.FromAddr)
	if !exist {
		logger.Warn(map[string]interface{}{"[state] [Verify Deposit TX]": "destination account addr does not exist!"})
		return false
	}

	//检查账户nonce是否合法
	if currentNonce == txHandler.TxData.Nonce {
		return true
	}

	logger.Warn(map[string]interface{}{"[state] [Verify Deposit TX]": "nonce does not match!"})
	return false
}

func (txHandler DepositTxHandler) Commit(tries ...interface{}) bool {
	trie := tries[0]
	tempAccountTrie, ok := trie.(*AccountStateTrie)
	if !ok {
		err := &errors.UnknownStateTrieError{}
		logger.Error(map[string]interface{}{"[state] [Verify Deposit TX]": err})
		return false
	}

	//修改目的账户状态：加金额、nonce+1
	toAccountAddrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	toLeaf, toExist := tempAccountTrie.GetLeaf(toAccountAddrBytes)
	if !toExist {
		logger.Error(map[string]interface{}{"[state] [Commit Deposit TX]": "destination account addr does not exist!"})
		return false
	}

	toLeaf.CommitAssetChange(txHandler.TxData.Amount, txHandler.TxData.CoinSince)
	//如果nonce达到了配置里的最大nonce值，从0开始（为了区别账户创建时的最小随机数1），否则+1
	if toLeaf.Nonce == config.MaxAccountNonce.Int64() {
		toLeaf.Nonce = 0
	} else {
		toLeaf.Nonce += 1
	}

	batch := routine.AtomicRoutineBatch{}
	return batch.Add(&AccountCommitRoutine{
		Kvs: []StateKeyValue{{
			Key: toAccountAddrBytes,
			Leaf: toLeaf,
		}},
		Trie: tempAccountTrie,
	}).Execute()
}

func (txHandler DepositTxHandler) Undo(tries ...interface{}) bool {
	trie := tries[0]
	tempAccountTrie, ok := trie.(*AccountStateTrie)
	if !ok {
		err := &errors.UnknownStateTrieError{}
		logger.Error(map[string]interface{}{"[state] [Undo Deposit TX]": err})
		return false
	}

	//修改目的账户状态：减金额
	toAccountAddrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	toLeaf, toExist := tempAccountTrie.GetLeaf(toAccountAddrBytes)
	if !toExist {
		logger.Error(map[string]interface{}{"[state] [Undo Deposit TX]": "destination account addr does not exist!"})
		return false
	}

	toLeaf.UndoAssetChange(txHandler.TxData.Amount, txHandler.TxData.CoinSince)
	if toLeaf.Nonce == 0 {
		toLeaf.Nonce = config.MaxAccountNonce.Int64()
	} else {
		toLeaf.Nonce -= 1
	}

	key := ecdsa.StrToAccountBytes(txHandler.TxData.ToAddr)
	batch := routine.AtomicRoutineBatch{}
	return batch.Add(&AccountCommitRoutine{
		Kvs: []StateKeyValue{{
			Key: key,
			Leaf: toLeaf,
		}},
		Trie: tempAccountTrie,
	}).Execute()
}
